package src

import fir.{FirConfig, LinearPhaseFormFirWithStream}
import spinal.core.{SFix, SInt, when, _}
import spinal.lib._
import spinal.core.sim._

case class ArbitrarySamplingRateConverse(taps : Int, width : Int, rate : Double, coefficientConst : Array[Double]) extends Component{
  //Σ(k=0->order-1)h(k)x(n-k)
  //Multiple and summary
  val romLines = coefficientConst.length / taps
  val io = new Bundle {
    //val coefficient          = slave Stream (Vec(SFix(0 exp, 16 bits), taps))
    val input           = slave Stream (SFix(width - 1 exp, width bits))
    val output          = master Stream (SFix(width - 1 exp, width bits))
    val accumShiftBits  = in UInt(width bits)//val accumShiftBits: UInt = (Math.log(C.toDouble / L.toDouble) / Math.log(2)).toInt
    val accuracyFactor  = in UInt(width bits)//C
    val deltaInt     = in (AFix.U(width exp, width * 2 bits))
    val coefficientAddress   = out UInt(width bits)
  } simPublic()

  val vecArr = Vec(Vec(SFix(0 exp, 16 bits), taps), romLines)

  for (i <- 0 until romLines) {
    for (j <- 0 until taps) {
      vecArr(i)(j) := coefficientConst(j * romLines + i) * romLines
    }
  }

  //io.coefficient.ready := True
  io.output.valid := True
/*
  Fint = Fsout / Fsin
  ΦΔint = C / Fsint = C * Fin / Fsout
  ΦΔint累加产生Φaccum
  L * Φaccum / C 取整 = Φaccum 右移 log2(C) - log2(L)位
   */
  def NCOModule(accumResult : AFix, delta : AFix) = new Area{
    val inReadySwitch = Reg(Bits(1 bits)) init(0)
    io.input.ready := False
    io.output.valid := False
    when(accumResult + delta >= io.accuracyFactor.toAFix) {
      accumResult := (accumResult + delta - io.accuracyFactor.toAFix).truncated
      inReadySwitch := 1
    }.otherwise {
      accumResult := (accumResult + delta).truncated
      inReadySwitch := 0
    }
    when(inReadySwitch === 1) {
      io.input.ready := True
      io.output.valid := True
    }
  }

  val phiAccum = Reg(AFix.U(width exp, width * 2 bits)) init (0)
//  val column = Reg(UInt(width bits)) init (0)
  val phiDeltaInt = Reg(AFix.U(width exp, width * 2 bits)) init (0)
  val shiftBits = Reg(UInt(width bits)) init (0)
//  column := io.coefficientColumn
  phiDeltaInt := io.deltaInt
  shiftBits := io.accumShiftBits
  io.input.ready.allowOverride
  io.output.valid.allowOverride
  val interpolation = (rate >= 1) generate new Area{
    //变量定义
    //val fint = fout / fin //插值倍数


    //相位累加
    NCOModule(phiAccum, phiDeltaInt)

    val phiShift : UInt = (phiAccum.asUInt() >> shiftBits) >> width
    io.coefficientAddress := phiShift.resized
    //FIR滤波
    val inputReg = Reg(SFix(width - 1 exp, width bits)) init(0)
    when(io.input.ready){
      inputReg := io.input.payload
    }

    val hist = History(that = inputReg, length = taps, when = io.input.ready, init = toSFix(0))
    val multiResult = (hist, vecArr(phiShift.resized)).zipped.map((x, y) => x * y)
    val summaryResult = multiResult.reduceBalancedTree(_ + _)

    io.output.valid := True
    io.output.payload := summaryResult.truncated
  }
  val decimation = (rate < 1) generate new Area{
    //相位累加
    NCOModule(phiAccum, phiDeltaInt)

    val resultReg = Reg(SFix(width - 1 exp, width bits)) init (0)
    when(io.output.valid) {
      resultReg := io.input.payload
      io.output.payload := io.input.payload
    }.otherwise {
      io.output.payload := resultReg
    }
  }
}

case class DecimationSampleRateConversion(intTaps : Int, decTaps : Int, width : Int, coefficientConst : Array[Double]) extends Component{
  val interpolateModule = ArbitrarySamplingRateConverse(intTaps, width, 2, coefficientConst)
  val decimationModule = ArbitrarySamplingRateConverse(decTaps, width, 0, coefficientConst)
  interpolateModule.io.output.payload <> decimationModule.io.input.payload
}
object SrcVerilogWithCustomConfig {
  def main(args: Array[String]) {
    val coefficientConst = Array[Double](
      //-0.00152884475502033, -0.00190413765156085, -0.00251201020053917, -0.00315172285923541, -0.00338157483002662, -0.00256899869677061, 1.4330398689852E-18, 0.00497037076557457, 0.0127558532986817, 0.023399631051306, 0.036490180152569, 0.0511553725692717, 0.0661431077396454, 0.0799794721992498, 0.0911792726013163, 0.0984722196424889, 0.101003617946099, 0.0984722196424889, 0.0911792726013163, 0.0799794721992498, 0.0661431077396454, 0.0511553725692717, 0.036490180152569, 0.023399631051306, 0.0127558532986817, 0.00497037076557457, 1.4330398689852E-18, -0.00256899869677061, -0.00338157483002662, -0.00315172285923541, -0.00251201020053917, -0.00190413765156085, -0.001528845
      //-0.00697814394109520, -0.0103696475300266, 0.00102743170269111, 0.0383281059702203, 0.0999719193228679, 0.166999478464426, 0.211020856010917, 0.211020856010917, 0.166999478464426, 0.0999719193228679, 0.0383281059702203, 0.00102743170269111, -0.0103696475300266, -0.00697814394109520
      //-0.00306200334634002,	-0.00503110836782698,	-0.00677269121762658,	2.87012324819924E-18,	0.0255476989130046,	0.0730833221416457,	0.132472846946078,	0.182615819497229,	0.202292230867672,	0.182615819497229,	0.132472846946078,	0.0730833221416457,	0.0255476989130046,	2.87012324819924E-18,	-0.00677269121762658,	-0.00503110836782698,	-0.003062003
      -0.000262862825969905, 6.11523137053542e-05, 0.000565590346895291, 0.00146095565006740, 0.00296270382571987, 0.00526470907677153, 0.00851291268392641, 0.0127821473845232, 0.0180589041703863, 0.0242322593883240, 0.0310943652433647, 0.0383509117688612, 0.0456409012211598, 0.0525640550027438, 0.0587133135993919, 0.0637092900253034, 0.0672332672398216, 0.0690554238850042, 0.0690554238850042, 0.0672332672398216, 0.0637092900253034, 0.0587133135993919, 0.0525640550027438, 0.0456409012211598, 0.0383509117688612, 0.0310943652433647, 0.0242322593883240, 0.0180589041703863, 0.0127821473845232, 0.00851291268392641, 0.00526470907677153, 0.00296270382571987, 0.00146095565006740, 0.000565590346895291, 6.11523137053542e-05, -0.000262862825969905
    )
    FirConfig.generateVerilog(new ArbitrarySamplingRateConverse(4,8, 4, coefficientConst))
  }
}